# -*- coding: utf-8 -*-
"""
Module Description: 模型基类
Date:2018/8/2
Anchor:Bai Jin Ping
"""
from datetime import datetime, date

from framework.dal.orm.controller_api import ORMController
from framework.dal.orm.models.attributes import *


__all__ = ['Model']


INDEX = (IntegerField, DateTimeField, DateField, TimeField,
         TimeStampField, FloatField, DictField, ListField, CharField)


class ModelBase(type):
    def __init__(cls, name, bases, attrs):
        # 调用type的__init__()初始化为元类
        super(ModelBase, cls).__init__(name, bases, attrs)
        cls.controller = ORMController

        # 存完字段后转成tuple
        cls._pk_field_list = list()
        cls._pk_field_eq_list = list()
        cls._attributes = {}
        for k, v in attrs.items():
            if isinstance(v, Attribute):
                cls._attributes[k] = v
                v.name = v.name or k
            elif k == '__name__':
                cls.__name__ = v
            if getattr(v, "primary_key", False):
                cls._pk_field_list.append(k)
                cls._pk_field_eq_list.append(k + "__eq")
        cls._pk_field_tuple = tuple(cls._pk_field_list)
        cls._pk_field_eq_tuple = tuple(cls._pk_field_eq_list)
        del cls._pk_field_list
        del cls._pk_field_eq_list

    def base_get_pk_field_tuple(cls):
        return cls._pk_field_tuple

    def base_get_pk_field_eq_tuple(cls):
        return cls._pk_field_eq_tuple


# Python 2/3 compatibility helpers. These helpers are used internally and are
# Reference from peewee orm
_METACLASS_ = '_metaclass_helper_'


def with_metaclass(meta, base=object):
    return meta(_METACLASS_, (base,), {})


class Model(with_metaclass(ModelBase)):

    __metaclass__ = ModelBase

    def __init__(self, **kwargs):
        # 判断是否是新model
        self._isnew = True

        # 判断是否只读model
        self._readonly = False

        # 写时复制的记录字典
        self._update_temp_dict = {}

        # 更新字段值
        self._update_attributes(**kwargs)

    @property
    def is_new(self):
        """
        是否新的记录对象

        从db查询到的全部不是新对象
        :return:
        """
        return self._isnew

    @property
    def readonly(self):
        """
        是否只读对象

        只读对象无法修改字段值, 也无法对其进行save()和delete()操作
        :return:
        """
        return self._readonly

    def _update_attributes(self, **kwargs):
        """
        根据给定的值更新model，但不保存
        :param kwargs: 字段与值得键值对
        """
        if not kwargs:
            return

        attrs = self.attributes().values()
        for att in attrs:
            if att.name in kwargs:
                att.__set__(self, kwargs[att.name])

    def save(self):
        """
        保存模块
        :return:True/False
        """
        if self.readonly:
            raise RuntimeError('Can not save readonly model!')

        # 新建model为插入，查询获得的model为更新
        if self._isnew:
            res = self.controller.insert(self)
        else:
            res = self.controller.update(self)
        return res

    def update(self):
        """
        更新模块模块
        :return:True/False
        """
        if self.readonly:
            raise RuntimeError('Can not update readonly model!')

        res = self.controller.update(self)
        if res:
            self._isnew = False
        return res

    def delete(self):
        """
        删除模块
        :return: True/False
        """
        if self.readonly:
            raise RuntimeError('Can not delete readonly model!')

        res = self.controller.delete(self)
        if res:
            self._isnew = True
        return res

    @classmethod
    def get_primary_keys(cls):
        """获取主键"""
        return cls.base_get_pk_field_tuple()

    @classmethod
    def get_all_eq_primary_keys(cls):
        """获取所有主键的__eq形式"""
        return cls.base_get_pk_field_eq_tuple()

    @property
    def attributes_dict(self):
        """
        (对象方法)获取一个字典
        {字段1：字段值1, 字段2：字段值2,字段3：字段值3,...}
        """
        h = {}
        for k in self.attributes().keys():
            h[k] = getattr(self, k)
        return h

    @classmethod
    def attributes(cls):
        """
        (类方法)获取一个字典
        {字段1：字段对象1, 字段2：字段对象2,字段3：字段对象3,...}
        """
        return dict(cls._attributes)

    def for_storage_dict(self):
        """
        (对象方法)获取一个用于存储的字典
        {字段1：存储值1, 字段2：存储值2,字段3：存储值3,...}
        """
        h = {}
        # attributes
        for k, v in self.attributes().items():
            if isinstance(v, DateTimeField):
                if v.auto_now:
                    setattr(self, k, datetime.now())
                if v.auto_now_add:
                    setattr(self, k, datetime.now())
            elif isinstance(v, DateField):
                if v.auto_now:
                    setattr(self, k, date.today())
                if v.auto_now_add:
                    setattr(self, k, date.today())
            for_storage = getattr(self, k)
            if for_storage is not None:
                # k = k.decode('utf-8')
                k = str(k)
                h[k] = v.typecast_for_storage(for_storage)
        return h

    @classmethod
    def attrs_list(cls):
        """
        (类方法)获取一个字段组成的列表
        [字段1,字段2,字段3...]
        """
        l = []
        for k, v in cls.__dict__.items():
            # Meta类没有__class__属性
            if hasattr(v, '__class__') and issubclass(v.__class__, Attribute):
                l.append(k)
        return l

    @property
    def fields(self):
        """
        获取一个字段对象组成的列表
        [字段对象1, 段对象2, 字段对象3,...]
        """
        return self.attributes().values()

    def for_update_dict(self):
        """
        (对象方法)获取一个用于更新的的字典
        {字段1：存储值1, 字段2：存储值2,字段3：存储值3,...}
        """
        h = {}
        for k, v in self._update_temp_dict.items():
            h[k] = self.attributes()[k].typecast_for_storage(v)

        return h

    def clear_update_dict(self):
        """
        (对象方法)清空用于更新的的字典
        """
        self._update_temp_dict = dict()
